<?php


namespace app\cms\community;


use app\cms\community\thirdPartyApi\aliyun\lib\config;
use app\cms\community\thirdPartyApi\aliyun\OSS\OSSFileBase;
use app\cms\dto\replyInfo;
use app\cms\model\replyModel;
use app\cms\model\resourcesModel;
use app\cms\model\shortLinkModel;
use app\community\sms\smsUtil;
use Exception;
use iflow\auth\Authorize\AuthAnnotation;
use iflow\Helper\Str\Str;
use iflow\Response;
use iflow\Router\Controller;
use iflow\Router\implement\Request\{ GetMapping, PostMapping };
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

#[Controller('cms/api/community/tool')]
class tool
{

    /**
     * 保存文件
     * @param int $status
     * @return Response
     */
    #[PostMapping]
    #[AuthAnnotation('save_file', '*')]
    public function saveFile(int $status = 1): Response
    {
        try {
            $files = [];
            $uploads = request()->file('file');

            foreach ($uploads as $file) {
                $path = $file->move('runtime/store/file', [
                    'type' => 'md5'
                ]);

                if (is_array($path)) {
                    $files[] = [
                        'resources_id' => Str::genUuid(),
                        'resources_path' => $path['path'],
                        'uid' => session('userInfo')['uid'],
                        'status' => $status,
                        'create_time' => time(),
                        'update_time' => time()
                    ];
                }
            }
            return $files ? resourcesModel::saveResources($files) : message()->update_failed('上传文件失败， 请重试');
        } catch (Exception $exception) {
            return message()->update_failed($exception -> getMessage());
        }
    }

    /**
     * OSS上传文件回调
     * @return Response
     * @throws Exception
     */
    #[PostMapping]
    #[AuthAnnotation('saveOssFile', '*')]
    public function ossSaveFile(): Response
    {
        // oss存储文件
        $data = request() -> postParams();

        if (empty($data['resources_path'])) return message() -> parameter_error('上传文件失败,缺少文件参数');

        $create = resourcesModel::create([
            'resources_id' => $data['file_uuid'],
            'resources_path' => $data['resources_path'],
            'uid' => session('userInfo')['uid'],
            'status' => $data['status']
        ]) -> toArray();
        return $create ? message() -> success('上传文件成功', $create)
            : message() -> update_failed('上传文件失败');
    }

    /**
     * 获取OSS Web直传
     * @param int $config_id
     * @param int $status
     * @return Response
     * @throws Exception
     */
    #[GetMapping]
    #[authAnnotation('saveOssFile', '*')]
    public function genOssWebUrl(int $config_id, int $status = 1): Response
    {
        $uuid = Str::genUuid();
        $ossConfig = new config($config_id);

        $url = parse_url($ossConfig -> getConfig()['endpoint']);
        $bucket = explode('.', $url['host'] ?? $url['path'])[0];
        $callBackBody = 'file_path=${object}&size=${size}&mimeType=${mimeType}';
        $callBackBody .= '&authorization='.request() -> getHeader('authorization');
        $callBackBody .= '&file_uuid='.$uuid;
        // oss:bucket:object:config_id
        $callBackBody .= '&resources_path=oss:'.$bucket.':${object}'.':'.$config_id;
        $callBackBody .= '&status='.$status;

        $params = (new OSSFileBase($ossConfig)) -> getOssWebUrl(
                'cms/file/'.date('Y-m-d').'/',
                36000,
                [
                    'callbackUrl' => request() -> getHeader('host').'/cms/api/community/tool/oss_save_file',
                    'callbackBody' => $callBackBody,
                    'callbackBodyType' => "application/json"
                ]
            );
        $params['uuid'] = $uuid;
        return message()->success('success', $params);
    }

    /**
     * 获取文件
     * @param string $resources_id
     * @param string $key
     * @return Response
     * @throws Exception
     */
    #[GetMapping('get_file/<?:resources_id>')]
    public function getFile(string $resources_id, string $key): Response
    {
        $file = resourcesModel::where([
            'resources_id' => $resources_id
        ])->findOrEmpty();
        if ($file->isExists()) {
            $needPwd = $file['resources_pwd'] !== '-1';
            $resourcesType = explode(':', $file['resources_path']);

            // 当不需要密码且文件状态为公共时
            if (!$needPwd && intval($file['status']) === 1) {
                if ($resourcesType[0] === 'oss') {
                    array_shift($resourcesType);
                    return getOssUrl(...$resourcesType);
                }
                return sendFile($file['resources_path'], isConfigRootPath: false);
            }

            // 验证是否需要密码
            if ($needPwd && $key === '') {
                return message()->unauthorized_error('请输入文件密码， 后进行访问');
            }

            // 验证密码是否正确
            if ($needPwd && $key === $file['resources_pwd']) {
                if ($resourcesType[0] === 'oss') {
                    array_shift($resourcesType);
                    return getOssUrl(...$resourcesType);
                }
                return sendFile($file['resources_path'], isConfigRootPath: false);
            }

            // 验证资源文件是否为私有
            $userInfo = session('userInfo');
            $uid = $userInfo ? $userInfo['uid'] : '';
            if (intval($file['status']) === 2 && $file['uid'] == $uid) {
                if ($resourcesType[0] === 'oss') {
                    array_shift($resourcesType);
                    return getOssUrl(...$resourcesType);
                }
                return sendFile($file['resources_path'], isConfigRootPath: false);
            }
        }
        return message()->nodata("文件不存在， 或无权访问");
    }

    /**
     * 提交评论
     * @param replyInfo|null $replyInfo
     * @return Response
     * @throws Exception
     */
    #[PostMapping]
    #[authAnnotation('reply', '*')]
    public function postReply(?replyInfo $replyInfo = null): Response
    {
        if ($replyInfo->reply === '') return message()->parameter_error('评论内容不能为空');
        return replyModel::addReply($replyInfo);
    }

    /**
     * 获取评论
     * @param int $form_id
     * @param int $id
     * @return Response
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    #[GetMapping]
    public function getReply(int $form_id, int $id): Response
    {
        return (new replyModel())->getReplyList($form_id, $id);
    }

    /**
     * 发送验证信息
     * @param string $to
     * @param string $sms_service
     * @param string $sms_model
     * @return Response
     */
    #[PostMapping]
    public function sms(string $to, string $sms_service, string $sms_model): Response
    {
        try {
            $client_config = [
                'to' => $to,
                'sms_service' => $sms_service,
                'sms_model' => $sms_model
            ];

            validator([
                'to' => 'required|email',
                'sms_service' => 'required',
                'sms_model' => 'required'
            ], $client_config, [
                'to.require' => '手机号或邮箱不能为空',
                'to.email' => '邮箱格式错误',
                'sms_service.require' => '请选择运营商',
                'sms_model.require' => '请选择发送事件'
            ]);

            $sms = new smsUtil('sms_service', $client_config);

            $msg = $sms->setup();

            if ($msg !== true) {
                return message()->update_failed($msg);
            }
            return message()->success('信息发送成功，请注意查收', [
                'uuid' => $sms->getUuid()
            ]);
        } catch (Exception $e) {
            return message()->parameter_error($e->getMessage());
        }
    }

    /**
     * 生成短链
     * @param string $url
     * @return Response
     */
    #[PostMapping]
    public function saveShortUrl(string $url): Response
    {
        return (new shortLinkModel()) -> saveShortUrl($url);
    }
}